package com.ardf.service.impl;

import com.alibaba.excel.EasyExcel;
import com.ardf.common.EntityConstants;
import com.ardf.entity.*;
import com.ardf.entity.dto.*;
import com.ardf.mapper.*;
import com.ardf.service.IResultService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author ShiYunHao
 * @since 2025-01-06
 */
@Service
@Slf4j
public class ResultServiceImpl extends ServiceImpl<ResultMapper, Result> implements IResultService {
    private final ResultMapper resultMapper;
    private final AlgorithmMapper algorithmMapper;
    private final GradeMapper gradeMapper;
    private final ProjectMapper projectMapper;
    private final RuleMapper ruleMapper;
    // 从配置文件中注入文件存储路径
    @Value("${file.upload-dir}")
    private String uploadDir;

    public ResultServiceImpl(ResultMapper resultMapper, AlgorithmMapper algorithmMapper, GradeMapper gradeMapper,
                             ProjectMapper projectMapper, RuleMapper ruleMapper) {
        this.resultMapper = resultMapper;
        this.algorithmMapper = algorithmMapper;
        this.gradeMapper = gradeMapper;
        this.projectMapper = projectMapper;
        this.ruleMapper = ruleMapper;
    }

    @Override
    public List<ResultMenuDto> getResultMenu(Long ruleId) {
        List<Algorithm> algorithms = algorithmMapper.selectList(new LambdaQueryWrapper<Algorithm>()
                .eq(Algorithm::getRuleId, ruleId)
                .orderByAsc(Algorithm::getType));
        return algorithms.stream().filter(algorithm -> {
            Long count = resultMapper.selectCount(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithm.getId()));
            return count != null && count != 0;
        }).map(algorithm -> {
            ResultMenuDto resultMenuDto = new ResultMenuDto();
            resultMenuDto.setAlgorithmId(algorithm.getId());
            resultMenuDto.setAlgorithmName(EntityConstants.ALGORITHM_TYPE_NAME_MAP.get(algorithm.getType()));
            resultMenuDto.setAlgorithmType(algorithm.getType());
            resultMenuDto.setIsLast(EntityConstants.ALGORITHM_STATUS_NO_AGREED_FINAL.equals(algorithm.getStatus()) ||
                    EntityConstants.ALGORITHM_STATUS_AGREED_FINAL.equals(algorithm.getStatus()));
            return resultMenuDto;
        }).toList();
    }

    @Override
    public Page<GradeInfoPersonTableDto> searchInfoPersonAll(Integer pageNum, Integer pageSize, Long projectId, Long groupId, String searchAll) {
        Page<GradeInfoPersonTableDto> page = new Page<>(pageNum, pageSize);
        return resultMapper.searchInfoPersonAll(page, projectId, groupId, searchAll);
    }

    @Override
    @Transactional
    public void calculateResult(Long algorithmId, Long ruleId) {
        Rule rule = ruleMapper.selectById(ruleId);
        Algorithm algorithm = algorithmMapper.selectById(algorithmId);
        Project project = projectMapper.selectById(rule.getProjectId());
        List<Grade> effectiveGrades;
        List<Grade> notEffectiveGrades;
        if (EntityConstants.PROJECT_CATEGORY_RELAY.equals(project.getCategory())) { //接力
            effectiveGrades = gradeMapper.listRelayEffectiveOrNot(
                    EntityConstants.GRADE_STATUS_YES, rule.getProjectId(), rule.getGroupId());
            notEffectiveGrades = gradeMapper.listRelayEffectiveOrNot(
                    EntityConstants.GRADE_STATUS_NO, rule.getProjectId(), rule.getGroupId());
        } else { //个人
            effectiveGrades = gradeMapper.listPersonEffectiveOrNot(
                    EntityConstants.GRADE_STATUS_YES, rule.getProjectId(), rule.getGroupId());
            notEffectiveGrades = gradeMapper.listPersonEffectiveOrNot(
                    EntityConstants.GRADE_STATUS_NO, rule.getProjectId(), rule.getGroupId());
        }
        for (Grade notEffectiveGrade : notEffectiveGrades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithm.getId())
                    .eq(Result::getGradeId, notEffectiveGrade.getId()));
            if (result != null) { //第二次计算同一个算法执行
                resultMapper.deleteById(result);
            }
            //有效站数和排名是空的
            result = new Result();
            result.setAlgorithmId(algorithm.getId());
            result.setGradeId(notEffectiveGrade.getId());
            resultMapper.insert(result);
        }
        //用代理对象调用事务方法会开启事务
        ResultServiceImpl currentProxy = (ResultServiceImpl) AopContext.currentProxy();
        if (EntityConstants.ALGORITHM_TYPE_NO_ORDER.equals(algorithm.getType())) {//无顺序
            currentProxy.calculateNoOrder(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_FIRST.equals(algorithm.getType())) {//有顺序，不能反悔，取第一个站开始算的最长有效子路线
            currentProxy.calculateOrderNoBackFirst(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_ORDER_BACK_EFFECTIVE.equals(algorithm.getType())) {//有顺序，能反悔，取最长有效子路线
            currentProxy.calculateOrderBackEffective(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_ORDER_NO_BACK_EFFECTIVE.equals(algorithm.getType())) {//有顺序，不能反悔，取最长有效子路线
            currentProxy.calculateOrderNoBackEffective(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_RELAY_NO_ORDER.equals(algorithm.getType())) {//接力赛无顺序
            currentProxy.calculateRelayNoOrder(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_FAST_NO_ORDER.equals(algorithm.getType())) {//快速赛无顺序
            currentProxy.calculateFastNoOrder(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_SUNLIGHT_ORDER.equals(algorithm.getType())) {//阳光严格有顺序
            currentProxy.calculateSunlightOrder(algorithmId, effectiveGrades, rule);
        } else if (EntityConstants.ALGORITHM_TYPE_SUNLIGHT_RELAY_ORDER.equals(algorithm.getType())) {//阳光接力严格有顺序
            currentProxy.calculateSunlightRelayOrder(algorithmId, effectiveGrades, rule);
        } else {
            throw new RuntimeException("未知算法类型");
        }
    }

    @Transactional
    public void calculateSunlightOrder(Long algorithmId, List<Grade> grades, Rule rule) {
        System.out.println("------------");
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            System.out.println("------------");
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();

                System.out.println(routes);
                StringJoiner stringJoiner = new StringJoiner("-");
                for (String route : routes) {
                    stringJoiner.add(route);
                }
                String realRoute = deduplicateRoute(grade.getRoute());
                System.out.println(realRoute+","+stringJoiner);
                if (realRoute.equals(stringJoiner.toString())) {
                    result.setNumber(routes.size());
                } else {
                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                    result.setNumber(null);
                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }


    @Transactional
    public void calculateFastNoOrder(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                String[] splitRuleRoute = rule.getRoute().split("S");
                List<String> splitRuleRouteOne = Arrays.stream(splitRuleRoute[0].split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s)|| "".equals(s))).toList();
                List<String> splitRuleRouteTwo = Arrays.stream(splitRuleRoute[1].split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s) || "".equals(s))).toList();
                String realRoute = deduplicateRoute(grade.getRoute());
                int number = 0;
                if (realRoute.contains("S")) {
                    number++;
                    int i = realRoute.indexOf("S");
                    String splitGradeRouteOne = realRoute.substring(0, i);
                    String splitGradeRouteTwo;
                    if (i == realRoute.length() - 1) {
                        splitGradeRouteTwo = "";
                    } else {
                        splitGradeRouteTwo = realRoute.substring(i + 1);
                    }
                    String[] split = splitGradeRouteTwo.split("-");
                    if ("MO".equals(split[split.length - 1])) {
                        List<String> listOne = Arrays.stream(splitGradeRouteOne.split("-")).filter(s -> !("".equals(s))).distinct().toList();
                        List<String> listTwo = Arrays.stream(splitGradeRouteTwo.split("-")).filter(s -> !("".equals(s))).distinct().toList();
                        System.out.println(listOne +","+listTwo);
                        System.out.println(splitRuleRouteOne +","+splitRuleRouteTwo);
                        for (String s : listOne) {
                            if (splitRuleRouteOne.contains(s)) {
                                number++;
                            }
                        }
                        for (String s : listTwo) {
                            if (splitRuleRouteTwo.contains(s)) {
                                number++;
                            }
                        }
                    } else {
                        List<String> listOne = Arrays.stream(splitGradeRouteOne.split("-")).filter(s -> !("".equals(s))).distinct().toList();
                        for (String s : listOne) {
                            if (splitRuleRouteOne.contains(s)) {
                                number++;
                            }
                        }
                    }
                } else {
                    String[] split = realRoute.split("-");
                    if ("MO".equals(split[split.length - 1])) {
                        List<String> list = Arrays.stream(split).filter(s -> !("".equals(s))).distinct().toList();
                        for (String s : list) {
                            if (splitRuleRouteTwo.contains(s)) {
                                number++;
                            }
                        }
                    } else {
                        number = 0;
                    }
                }
                result.setNumber(number);
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    @Transactional
    public void calculateOrderNoBackEffective(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
                String realRoute = deduplicateRoute(grade.getRoute());
                String[] split = realRoute.split("-");
//                if ("MO".equals(split[split.length - 1])) {
                    int number = 0;
                    for (int i = 0; i < split.length; i++) {
                        int temp = 0;
                        int recentIndex = -1;
                        for (int j = i; j < split.length; j++) {
                            if (routes.indexOf(split[j]) > recentIndex) {
                                recentIndex = routes.indexOf(split[j]);
                                temp++;
                            }
                        }
                        if (temp > number) {
                            number = temp;
                        }
                    }
                    result.setNumber(number);
//                } else {
//                    result.setNumber(null);
//                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
//                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    @Transactional
    public void calculateOrderBackEffective(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
                String realRoute = deduplicateRoute(grade.getRoute());
                List<String> split = Arrays.stream(realRoute.split("-")).filter(s -> !s.isEmpty()) // 过滤掉空字符串
                        .collect(Collectors.toList());
                System.out.println(split.stream().toList() + "," +split.size());
//                if ("MO".equals(split.get(split.size() - 1))) {
                    int number = 0;
                    for (int i = 0; i < split.size(); i++) {
                        List<AbstractMap.SimpleEntry<Integer, String>> tempList = new ArrayList<>();
                        ArrayList<AlgorithmUseDto> tempEntrys = new ArrayList<>();//存被认可的点
                        for (int j = i; j < split.size(); j++) {
                            if (tempList.isEmpty()) {
                                tempList.add(new AbstractMap.SimpleEntry<>(j, split.get(j)));
                            } else {
                                if (routes.indexOf(split.get(j)) > routes.indexOf(tempList.get(tempList.size() - 1).getValue())) {
                                    tempList.add(new AbstractMap.SimpleEntry<>(j, split.get(j)));
                                } else {
                                    if (tempList.size() > 1) {
                                        int t = tempList.size() - 2;
                                        for (int t1 = t; t1 >= 0; t1--) {
                                            if (routes.indexOf(split.get(j)) > routes.indexOf(tempList.get(t1).getValue())) {
                                                if (!tempEntrys.contains(new AlgorithmUseDto(new ArrayList<>(tempList.subList(0, t1 + 1)), j))) {
                                                    tempEntrys.add(new AlgorithmUseDto(new ArrayList<>(tempList.subList(0, t1 + 1)), j));
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        if (tempList.size() > number) {
                            number = tempList.size();
                        }
                        while (tempEntrys.size() != 0) {
                            tempList.clear();
                            AlgorithmUseDto algorithmUseDto = tempEntrys.get(0);
                            tempList.addAll(algorithmUseDto.getTempList());
                            for (int j = algorithmUseDto.getSecond(); j < split.size(); j++) {
                                if (routes.indexOf(split.get(j)) > routes.indexOf(tempList.get(tempList.size() - 1).getValue())) {
                                    tempList.add(new AbstractMap.SimpleEntry<>(j, split.get(j)));
                                } else {
                                    if (tempList.size() > 1) {
                                        int t = tempList.size() - 2;
                                        for (int t1 = t; t1 >= 0; t1--) {
                                            if (routes.indexOf(split.get(j)) > routes.indexOf(tempList.get(t1).getValue())) {
                                                tempEntrys.add(new AlgorithmUseDto(new ArrayList<>(tempList.subList(0, t1 + 1)), j));
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if (tempList.size() > number) {
                                number = tempList.size();
                            }
                            tempEntrys.remove(0);
                        }
                    }
                    result.setNumber(number);
//                } else {
//                    result.setNumber(null);
//                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
//                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    @Transactional
    public void calculateOrderNoBackFirst(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
                String realRoute = deduplicateRoute(grade.getRoute());
                String[] split = realRoute.split("-");
//                if ("MO".equals(split[split.length - 1])) {
                    int number = 0;
                    int recentIndex = -1;
                    for (String s : split) {
                        if (routes.indexOf(s) > recentIndex) {
                            recentIndex = routes.indexOf(s);
                            number++;
                        }
                    }
                    result.setNumber(number);
//                }
//                else {
//                    result.setNumber(null);
//                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
//                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;


        for (int i = 0; i < resultWithTimeList.size(); i++) {
            System.out.println(resultWithTimeList.get(i));

            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }


        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    @Transactional
    public void calculateSunlightRelayOrder(Long algorithmId, List<Grade> grades, Rule rule) {
        System.out.println("999999999999999999");
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
                int validNum= routes.size()/3;

                String realRoute = deduplicateRoute(grade.getRoute());
                String[] routeChild = realRoute.split("MO");
                int routeChildSize = 0;
                String[] split = realRoute.split("-");
//                if ("MO".equals(split[split.length - 1])) {
//                    routeChildSize = Math.min(routeChild.length, 3);
//                } else {
                    if (routeChild.length < validNum) {
                        routeChildSize = routeChild.length;
                    } else {
                        routeChildSize = validNum;
                    }
//                }
                StringJoiner stringJoiner = new StringJoiner("-");
                for (int i = 0; i < routeChildSize; i++) {
                    Arrays.stream(routeChild[i].split("-"))
                            .filter(s -> !"MO".equals(s))
                            .filter(s -> !"".equals(s))
                            .limit(validNum)
                            .forEach(stringJoiner::add);
                }
                if ("MO".equals(routes.get(routes.size() - 1))) {
                    stringJoiner.add("MO");
                }

                System.out.println(stringJoiner+","+String.join("-", routes));

                if (String.join("-", routes).equals(stringJoiner.toString())) {
                    result.setNumber(routes.size());
                } else {
                    result.setNumber(null);
                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    /**
     * 路线去重
     */
    private String deduplicateRoute(String route) {
        final String[] routeE = {null};
        List<String> realRoute = Arrays.stream(route.split("-"))
                .filter(s -> !("起点".equals(s) || "终点".equals(s)))
                .filter(s -> {
                    if (s.equals(routeE[0])) {
                        return false;
                    } else {
                        routeE[0] = s;
                        return true;
                    }
                }).toList();
        StringJoiner stringJoiner = new StringJoiner("-");
        for (String s : realRoute) {
            stringJoiner.add(s);
        }
        return stringJoiner.toString();
    }

    @Transactional
    public void calculateRelayNoOrder(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> routes = Arrays.stream(rule.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s)))
                        .filter(s -> !"MO".equals(s)).toList();
                String realRoute = deduplicateRoute(grade.getRoute());
                int validNum= routes.size()/3;

                String[] routeChild = realRoute.split("MO");
                int routeChildSize;
                String[] split = realRoute.split("-");
//                if ("MO".equals(split[split.length - 1])) {
//                    routeChildSize = Math.min(routeChild.length, 3);
//                } else {
                    if (routeChild.length < validNum) {
                        routeChildSize = routeChild.length;
                    } else {
                        routeChildSize = validNum;
                    }
//                }
                Set<String> routeSet = new HashSet<>();
                for (int i = 0; i < routeChildSize; i++) {
                    List<String> list = Arrays.stream(routeChild[i].split("-"))
                            .filter(s -> !"MO".equals(s))
                            .filter(s -> !"".equals(s))
                            .distinct().limit(validNum)
                            .toList();
                    routeSet.addAll(list);
                }
                int number = 0;
                for (String s : routeSet) {
                    if (routes.contains(s)) {
                        number++;
                    }
                }
                result.setNumber(number);
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        //排序
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        //设置名次
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);
                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime()) || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }

    @Override
    public Page<GradeResultPersonTableDto> searchResultPersonAll(Integer pageNum, Integer pageSize, String searchAll, Long projectId, Long groupId, Long algorithmId) {
        Page<GradeResultPersonTableDto> page = new Page<>(pageNum, pageSize);
        return resultMapper.searchResultPersonAll(page, searchAll, projectId, groupId, algorithmId);
    }

    @Override
    @Transactional
    public void deleteByAlgorithmId(Long algorithmId) {
        resultMapper.delete(new LambdaQueryWrapper<Result>()
                .eq(Result::getAlgorithmId, algorithmId));
    }

    @Override
    public void downloadResultTable(HttpServletResponse response, Long algorithmId, Long projectId, Long groupId, Boolean isRelay) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = URLEncoder.encode("导出成绩结果表", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        if (isRelay) {
            List<DownloadResultRelayTableDto> list = resultMapper.getRelayAll(algorithmId, projectId, groupId);
            for (DownloadResultRelayTableDto downloadResultRelayTableDto : list) {
                if (downloadResultRelayTableDto.getTime() != null) {
                    downloadResultRelayTableDto.setTimeStr(downloadResultRelayTableDto.getTime().toString());
                }
                if (downloadResultRelayTableDto.getStatus() != null) {
                    if (downloadResultRelayTableDto.getStatus() == 1) {
                        downloadResultRelayTableDto.setStatusStr("有效");
                    } else {
                        downloadResultRelayTableDto.setStatusStr("无效");
                    }
                }
            }
            EasyExcel.write(response.getOutputStream(), DownloadResultRelayTableDto.class).sheet("表格1").doWrite(list);
        } else {
            List<DownloadResultPersonTableDto> list = resultMapper.getPersonAll(algorithmId, projectId, groupId);
            for (DownloadResultPersonTableDto downloadResultPersonTableDto : list) {
                if (downloadResultPersonTableDto.getTime() != null) {
                    downloadResultPersonTableDto.setTimeStr(downloadResultPersonTableDto.getTime().toString());
                }
                if (downloadResultPersonTableDto.getStatus() != null) {
                    if (downloadResultPersonTableDto.getStatus() == 1) {
                        downloadResultPersonTableDto.setStatusStr("有效");
                    } else {
                        downloadResultPersonTableDto.setStatusStr("无效");
                    }
                }
            }
            EasyExcel.write(response.getOutputStream(), DownloadResultPersonTableDto.class).sheet("表格1").doWrite(list);
        }
    }

    @Override
    public Page<GradeInfoRelayTableDto> searchInfoRelayAll(Integer pageNum, Integer pageSize, Long projectId, Long groupId, String searchAll) {
        Page<GradeInfoRelayTableDto> page = new Page<>(pageNum, pageSize);
        return resultMapper.searchInfoRelayAll(page, projectId, groupId, searchAll);
    }

    @Override
    public Page<GradeResultRelayTableDto> searchResultRelayAll(Integer pageNum, Integer pageSize, String searchAll, Long projectId, Long groupId, Long algorithmId) {
        Page<GradeResultRelayTableDto> page = new Page<>(pageNum, pageSize);
        return resultMapper.searchResultRelayAll(page, searchAll, projectId, groupId, algorithmId);
    }

    @Override
    @Transactional
    public String uploadPicture(MultipartFile file, Long gradeId) throws IOException {
        if (file.isEmpty()) {
            return null;
        }
        // 确保上传目录存在
        File uploadPath = new File(uploadDir);
        if (!uploadPath.exists() && !uploadPath.mkdirs()) {
            throw new IOException("无法创建上传目录: " + uploadDir);
        }

        // 生成唯一的文件名
        String originalFilename = file.getOriginalFilename();
        String fileExtension = originalFilename != null && originalFilename.contains(".") ?
                originalFilename.substring(originalFilename.lastIndexOf(".")) : "";
        String uniqueFileName = UUID.randomUUID() + fileExtension;

        // 构建文件存储路径
        Path filePath = Paths.get(uploadDir, uniqueFileName);
        // 将文件保存到本地
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
        Grade grade = gradeMapper.selectById(gradeId);
        if (grade.getPicture() != null) {
            //删除原图片
            try {
                Path path = Paths.get(grade.getPicture());
                Files.delete(path);
            } catch (Exception e) {
                log.warn("原照片已经删除");
            }
        }
        String picUri = filePath.toString().replace("\\", "/");
        grade.setPicture(picUri);
        gradeMapper.updateById(grade);
        return picUri;
    }

    @Override
    public List<Long> selectByGradeId(Long gradeId) {
        List<Result> results = resultMapper.selectList(new LambdaQueryWrapper<Result>().eq(Result::getGradeId,gradeId).select(Result::getAlgorithmId));
        List<Long> alIds = results.stream()
                .map(Result::getAlgorithmId)
                .collect(Collectors.toList());
        return alIds;
    }

    //    无顺序
    @Transactional
    public void calculateNoOrder(Long algorithmId, List<Grade> grades, Rule rule) {
        List<ResultWithTime> resultWithTimeList = new ArrayList<>();
        for (Grade grade : grades) {
            Result result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                    .eq(Result::getAlgorithmId, algorithmId)
                    .eq(Result::getGradeId, grade.getId()));
            if (result == null) {
                result = new Result();
                result.setAlgorithmId(algorithmId);
                result.setGradeId(grade.getId());
                resultMapper.insert(result);
                result = resultMapper.selectOne(new LambdaQueryWrapper<Result>()
                        .eq(Result::getAlgorithmId, algorithmId)
                        .eq(Result::getGradeId, grade.getId()));
            }
            if (!StringUtils.hasLength(grade.getRoute()) || !grade.getRoute().startsWith("起点") || !grade.getRoute().endsWith("终点") ||
                    grade.getTime() == null || grade.getTime().isAfter(rule.getLimitTime())) {
                grade.setStatus(EntityConstants.GRADE_STATUS_NO);
                result.setNumber(null);
            } else {//算法
                List<String> gradeRoute= Arrays.stream(grade.getRoute().split("-"))
                        .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
//                if (!"MO".equals(gradeRoute.get(gradeRoute.size()-1))) {
//                    result.setNumber(null);
//                    grade.setStatus(EntityConstants.GRADE_STATUS_NO);
//                } else {
                    int number = 0;
                    List<String> route = Arrays.stream(rule.getRoute().split("-"))
                            .filter(s -> !("起点".equals(s) || "终点".equals(s))).toList();
                    for (String s : route) {
                        if (gradeRoute.contains(s)) {
                            number++;
                        }
                    }
                    result.setNumber(number);
//                }
            }
            if (EntityConstants.GRADE_STATUS_NO.equals(grade.getStatus())) {
                resultMapper.update(new LambdaUpdateWrapper<Result>()
                        .set(Result::getNumber, null)
                        .eq(Result::getId, result.getId()));
                gradeMapper.updateById(grade);
            } else {
                ResultWithTime resultWithTime = new ResultWithTime();
                BeanUtils.copyProperties(result, resultWithTime);
                resultWithTime.setTime(grade.getTime());
                resultWithTimeList.add(resultWithTime);
            }
        }
        resultWithTimeList.sort((o1, o2) -> {
            if (o2.getNumber() - o1.getNumber() == 0) {
                if (o2.getTime().isBefore(o1.getTime())) {
                    return 1;
                } else if (o2.getTime().isAfter(o1.getTime())) {
                    return -1;
                } else {
                    return 0;
                }
            } else {
                return o2.getNumber() - o1.getNumber();
            }
        });
        Integer rank = 1;
        for (int i = 0; i < resultWithTimeList.size(); i++) {
            System.out.println(resultWithTimeList.get(i));
            if (i != 0) {
                ResultWithTime lastResultWithTime = resultWithTimeList.get(i - 1);
                ResultWithTime resultWithTime = resultWithTimeList.get(i);

                if (!lastResultWithTime.getTime().equals(resultWithTime.getTime())  || !lastResultWithTime.getNumber().equals(resultWithTime.getNumber())) {
                    rank++;
                }
            }
            resultWithTimeList.get(i).setRank(rank);
        }
        List<Result> list = resultWithTimeList.stream().map(resultWithTime -> {
            Result result = new Result();
            BeanUtils.copyProperties(resultWithTime, result);
            return result;
        }).toList();
        resultMapper.updateById(list);
    }
}
